class Node {
    constructor(id, type, inputs = [], outputs = []) {
        this.id = id;
        this.type = type;
        this.inputs = inputs;
        this.outputs = outputs;
        this.createElement();
    }

    createElement() {
        this.element = document.createElement('div');
        this.element.classList.add('node');
        this.element.style.left = `${Math.random() * 80}%`;
        this.element.style.top = `${Math.random() * 80}%`;
        this.element.draggable = true;

        const title = document.createElement('div');
        title.textContent = `Node ${this.id}`;
        this.element.appendChild(title);

        // 添加输入框
        this.inputs.forEach((input, index) => {
            const inputField = document.createElement('input');
            inputField.classList.add('input-field');
            inputField.type = 'text';
            inputField.placeholder = `Input ${index + 1}`;
            inputField.value = input;
            this.element.appendChild(inputField);

            const inputConnector = document.createElement('div');
            inputConnector.classList.add('connector', 'connector-left');
            inputConnector.style.top = `${20 + index * 20}px`;
            this.element.appendChild(inputConnector);

            inputConnector.addEventListener('dragover', (e) => {
                e.preventDefault();
            });

            inputConnector.addEventListener('drop', (e) => {
                const sourceId = e.dataTransfer.getData('text/plain');
                const targetId = this.id;
                if (sourceId !== targetId) {
                    flowchart.connectNodes(sourceId, targetId);
                }
            });
        });

        // 添加输出接口
        this.outputs.forEach((output, index) => {
            const outputConnector = document.createElement('div');
            outputConnector.classList.add('connector', 'connector-right');
            outputConnector.style.top = `${20 + index * 20}px`;
            this.element.appendChild(outputConnector);

            outputConnector.addEventListener('dragstart', (e) => {
                e.dataTransfer.setData('text/plain', this.id);
            });
        });

        document.getElementById('flowchart').appendChild(this.element);

        this.element.addEventListener('dragstart', (e) => {
            e.dataTransfer.setData('text/plain', this.id);
        });

        this.element.addEventListener('dragend', () => {
            flowchart.updateConnections();
        });
    }

    addInput(input) {
        this.inputs.push(input);
    }

    addOutput(output) {
        this.outputs.push(output);
    }

    toJSON() {
        return {
            id: this.id,
            type: this.type,
            inputs: this.inputs,
            outputs: this.outputs
        };
    }
}

class NodeFactory {
    constructor() {
        this.nodeTypes = {};
    }

    registerNodeType(type, nodeClass) {
        this.nodeTypes[type] = nodeClass;
    }

    createNode(type, id, inputs, outputs) {
        const NodeClass = this.nodeTypes[type];
        if (!NodeClass) {
            throw new Error(`Node type ${type} is not registered.`);
        }
        return new NodeClass(id, type, inputs, outputs);
    }

    createNodesFromJSON(json) {
        return json.map(nodeData => {
            const node = this.createNode(nodeData.type, nodeData.id, nodeData.inputs, nodeData.outputs);
            return node;
        });
    }
}

class CustomNode extends Node {
    constructor(id, inputs, outputs) {
        super(id, 'CustomNode', inputs, outputs);
    }
}

const nodeFactory = new NodeFactory();
nodeFactory.registerNodeType('CustomNode', CustomNode);

const jsonConfig = [
    {
        id: 'node1',
        type: 'CustomNode',
        inputs: ['Input 1', 'Input 2'],
        outputs: ['Output 1']
    },
    {
        id: 'node2',
        type: 'CustomNode',
        inputs: ['Input 3'],
        outputs: ['Output 2', 'Output 3']
    }
];

const nodes = nodeFactory.createNodesFromJSON(jsonConfig);

class Flowchart {
    constructor() {
        this.nodes = {};
        this.connections = [];
        this.svg = this.createSVGElement();
    }

    createSVGElement() {
        const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
        svg.style.position = 'absolute';
        svg.style.width = '100%';
        svg.style.height = '100%';
        document.getElementById('flowchart').appendChild(svg);
        return svg;
    }

    addNode(node) {
        this.nodes[node.id] = node;
    }

    removeNode(nodeId) {
        const node = this.nodes[nodeId];
        if (node) {
            node.element.remove();
            delete this.nodes[nodeId];
            this.connections = this.connections.filter(conn => conn.sourceId !== nodeId && conn.targetId !== nodeId);
            this.updateConnections();
        }
    }

    connectNodes(sourceId, targetId) {
        const sourceNode = this.nodes[sourceId];
        const targetNode = this.nodes[targetId];
        if (sourceNode && targetNode) {
            sourceNode.addOutput(targetId);
            targetNode.addInput(sourceId);
            this.connections.push({ sourceId, targetId });
            this.drawConnections();
        }
    }

    drawConnections() {
        while (this.svg.firstChild) {
            this.svg.removeChild(this.svg.firstChild);
        }
        this.connections.forEach(conn => {
            const sourceNode = this.nodes[conn.sourceId];
            const targetNode = this.nodes[conn.targetId];
            if (sourceNode && targetNode) {
                const sourceRect = sourceNode.element.getBoundingClientRect();
                const targetRect = targetNode.element.getBoundingClientRect();
                const startX = sourceRect.right;
                const startY = sourceRect.top + sourceRect.height / 2;
                const endX = targetRect.left;
                const endY = targetRect.top + targetRect.height / 2;

                const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
                const pathData = `M ${startX},${startY} C ${startX + 50},${startY} ${endX - 50},${endY} ${endX},${endY}`;
                path.setAttribute('d', pathData);
                path.setAttribute('stroke', 'black');
                path.setAttribute('fill', 'transparent');
                this.svg.appendChild(path);
            }
        });
    }

    updateConnections() {
        this.drawConnections();
    }

    toJSON() {
        return {
            nodes: Object.values(this.nodes).map(node => node.toJSON()),
            connections: this.connections
        };
    }
}

const flowchart = new Flowchart();
nodes.forEach(node => flowchart.addNode(node));

// Example connections
flowchart.connectNodes('node1', 'node2');
console.log(flowchart.toJSON());

// Enable dragging nodes
document.getElementById('flowchart').addEventListener('dragover', (e) => e.preventDefault());
document.getElementById('flowchart').addEventListener('drop', (e) => {
    e.preventDefault();
    const id = e.dataTransfer.getData('text/plain');
    const node = flowchart.nodes[id];
    if (node) {
        const rect = document.getElementById('flowchart').getBoundingClientRect();
        node.element.style.left = `${e.clientX - rect.left - node.element.clientWidth / 2}px`;
        node.element.style.top = `${e.clientY - rect.top - node.element.clientHeight / 2}px`;
        flowchart.updateConnections();
    }
});
